/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "time.h"
#include "TimeUtils.h"
#include "RenderServer.h"
#include "RenderThread.h"
#include "render_api.h"
#include "Win32PipeStream.h"


#include <set>
#include <string.h>

#define STREAM_BUFFER_SIZE 4*1024*1024

typedef std::set<RenderThread *> RenderThreadsSet;

RenderServer::RenderServer() :
    m_lock(),
    m_listenSock(NULL),
    m_exiting(false)
{
}

RenderServer::~RenderServer()
{
    delete m_listenSock;
}

RenderServer *RenderServer::create()
{
    RenderServer *server = new RenderServer();
    if (!server) {
        return NULL;
    }
    server->m_listenSock = new Win32PipeStream();
    return server;
}

intptr_t RenderServer::main()
{
    RenderThreadsSet threads;

    while(1) {
        SocketStream *stream = m_listenSock->accept();
        if (!stream) {
            fprintf(stderr,"Error accepting connection, aborting\n");
            break;
        }

        unsigned int clientFlags;
        if (!stream->readFully(&clientFlags, sizeof(unsigned int))) {
            fprintf(stderr,"Error reading clientFlags\n");
            delete stream;
            continue;
        }

        DBG("RenderServer: Got new stream!\n");

        // check if we have been requested to exit while waiting on accept
        if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) {
            m_exiting = true;
            delete stream;
            odprintf("ggg Exit server thread...");
            break;
        }

        RenderThread *rt = RenderThread::create(stream, &m_lock);
        if (!rt) {
            fprintf(stderr,"Failed to create RenderThread\n");
            delete stream;
        } else if (!rt->start()) {
            fprintf(stderr,"Failed to start RenderThread\n");
            delete rt;
            delete stream;
        }

        //
        // remove from the threads list threads which are
        // no longer running
        //
        for (RenderThreadsSet::iterator n,t = threads.begin();
             t != threads.end();
             t = n) {
            // first find next iterator
            n = t;
            n++;

            // delete and erase the current iterator
            // if thread is no longer running
            if ((*t)->isFinished()) {
                delete (*t);
                threads.erase(t);
            }
        }

        // if the thread has been created and started, insert it to the list
        if (rt) {
            threads.insert(rt);
            DBG("Started new RenderThread\n");
        }
    }

    //
    // Wait for all threads to finish
    //
    for (RenderThreadsSet::iterator t = threads.begin();
         t != threads.end();
         t++) {
        /*gao Add for wait thread. */
        (*t)->wait(NULL);
        delete (*t);
    }
    threads.clear();

    return 0;
}
